﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Drawing.Imaging;
//MicroDesigner
using Jc.MicroDesigner.Management;
using Jc.MicroDesigner.Objects;
using Jc.MicroDesigner.ToolWindows;

namespace Jc.MicroDesigner.Drawings
{
    /// <summary>
    /// Область рисования элементов
    /// </summary>
    public partial class DrawPanel : Panel
    {
        private ObjectManager _Manager = null;
        private IToolBox _ToolBoxManager = null;
        private SmoothingMode _DrawSmoothing = SmoothingMode.Default;
        private PixelFormat _DrawPixelFormat = PixelFormat.Format32bppPArgb;
        private InterpolationMode _Interpolation = InterpolationMode.HighQualityBicubic;

        private int _Discreteness = 0;
        private float _DrawingScale = 1.0f;

        private BaseElement _SelectedElement = null;

        /// <summary>
        /// Создать панель для рисования схемы
        /// </summary>
        public DrawPanel()
            : this(null)
        {

        }

        /// <summary>
        /// Создать панель для рисования схемы
        /// </summary>
        /// <param name="container">Контейнер</param>
        public DrawPanel(IContainer container)
        {
            if (container != null)
                container.Add(this);

            InitializeComponent();
            //BackColor = Color.White;
            //Стили для производительной отрисовки содержимого
            SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true);

            //Events
            this.MouseDown += new MouseEventHandler(DrawPanel_MouseDown);
            this.MouseUp += new MouseEventHandler(DrawPanel_MouseUp);
            this.MouseMove += new MouseEventHandler(DrawPanel_MouseMove);
            //Контекстные меню
            DeleteElementMenuItem.Click += new EventHandler(DeleteElementMenuItem_Click);
            PropertiesItem.Click += new EventHandler(PropertiesItem_Click);
            WorkSpaceProperties.Click += new EventHandler(WorkSpaceProperties_Click);
        }

        #region Events

        void DrawPanel_MouseMove(object sender, MouseEventArgs e)
        {
            if (_ToolBoxManager != null)
            {
                _ToolBoxManager.ActiveTool.OnMouseMove(this, e);
            }
        }

        void DrawPanel_MouseUp(object sender, MouseEventArgs e)
        {
            if (_ToolBoxManager != null)
            {
                _ToolBoxManager.ActiveTool.OnMouseUp(this, e);
            }
        }

        void DrawPanel_MouseDown(object sender, MouseEventArgs e)
        {
            if (_ToolBoxManager != null)
            {
                _ToolBoxManager.ActiveTool.OnMouseDown(this, e);
            }
        }

        private Image GenerateImage()
        {
            Image buffer = new Bitmap(
                    Convert.ToInt32(Math.Round(Width / _DrawingScale)),
                    Convert.ToInt32(Math.Round(Height / _DrawingScale)),
                    _DrawPixelFormat);
            Graphics graph = Graphics.FromImage(buffer);
            graph.PageScale = _DrawingScale;
            //graph.SmoothingMode = _DrawSmoothing;
            //graph.InterpolationMode = InterpolationMode.HighQualityBicubic;
            foreach (BaseElement el in _Manager.Elements)
            {
                // 1 рисуем каждый элемент в собственный буфер
                if ((el.DrawOptions.Width > 0) && (el.DrawOptions.Height > 0))
                {
                    Image el_img = el.DrawOptions.DrawToImage();
                    // 2 добавляем буфер элемента в буфер для холста
                    graph.DrawImage(el_img, el.DrawOptions.Left, el.DrawOptions.Top);
                }
            }
            return buffer;
        }

        /// <summary>
        /// Отрисовка элементов
        /// </summary>
        /// <param name="e">Аргументы</param>
        protected override void OnPaint(PaintEventArgs e)
        {
            if (_Manager != null)
            {
                e.Graphics.PageUnit = GraphicsUnit.Pixel;
                //буфер для элементов, размер выбирается с учётом масштаба
                Image buffer = GenerateImage();
                // 3 рисуем буфер холста
                e.Graphics.SmoothingMode = _DrawSmoothing;
                e.Graphics.InterpolationMode = _Interpolation;
                e.Graphics.DrawImage(buffer, ClientRectangle);
                //рисуем данные инструмента
                if (_ToolBoxManager != null)
                {
                    _ToolBoxManager.ActiveTool.OnPaintScheme(this, e.Graphics);
                }
            }
        }

        /// <summary>
        /// Удалить выбранный элемент с холста
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void DeleteElementMenuItem_Click(object sender, EventArgs e)
        {
            DeleteSelectedObject();
        }

        /// <summary>
        /// Просмотр свойств элемента
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void PropertiesItem_Click(object sender, EventArgs e)
        {
            if ((_SelectedElement != null) && (_Manager != null))
            {
                ObjPropertyWindow win = new ObjPropertyWindow();
                win.ShowDialog(_SelectedElement, _Manager);
                Invalidate();
            }
        }

        /// <summary>
        /// Редактирование холста
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void WorkSpaceProperties_Click(object sender, EventArgs e)
        {
            ShowCanvasProperties();
        }

        #endregion

        #region Methods

        /// <summary>
        /// Показать глобальное контекстное меню
        /// </summary>
        /// <param name="x">X</param>
        /// <param name="y">Y</param>
        public void ShowAreaMenu(int x, int y)
        {
            Point p = PointToScreen(new Point(x, y));
            AreaContextMenu.Show(p);
        }

        /// <summary>
        /// Показать контекстное меню элемента
        /// </summary>
        /// <param name="element">Элемент</param>
        /// <param name="x">X</param>
        /// <param name="y">Y</param>
        public void ShowElementMenu(BaseElement element, int x, int y)
        {
            _SelectedElement = element;
            Point p = PointToScreen(new Point(x, y));
            ElementContextMenu.Show(p);
        }

        /// <summary>
        /// Получить дискретные кординаты для поризвольной точки
        /// </summary>
        /// <param name="location">Точка</param>
        /// <returns>Результат</returns>
        public Point GetDiscreetCoord(Point location)
        {
            Point res = location;
            if (_Discreteness > 0)
            {
                res = new Point();
                int dx = location.X % _Discreteness;
                if (dx > _Discreteness / 2)
                    res.X = (1 + (location.X / _Discreteness)) * _Discreteness;
                else
                    res.X = location.X - dx;

                int dy = location.Y % _Discreteness;
                if (dy > _Discreteness / 2)
                    res.Y = (1 + (location.Y / _Discreteness)) * _Discreteness;
                else
                    res.Y = location.Y - dy;
            }
            return res;
        }

        /// <summary>
        /// Найти элемент по координатам
        /// </summary>
        /// <param name="x">X</param>
        /// <param name="y">Y</param>
        /// <returns>Элемент</returns>
        public BaseElement SearchElementByXY(int x, int y)
        {
            BaseElement res = null;
            if (_Manager != null)
            {
                List<BaseElement> elements = _Manager.Elements;
                int i = 0;
                while ((i < elements.Count) && (elements[i].DrawOptions.CheckSelection(x, y) == false))
                    i++;
                if (i < elements.Count)
                    res = elements[i];
            }
            return res;
        }

        /// <summary>
        /// Найти элементы, для которых запрещены пересечения, по координатам
        /// Запрещено пересекать проводом Элементы цепи за исключением проводов
        /// </summary>
        /// <param name="x">X</param>
        /// <param name="y">Y</param>
        /// <returns>Элементы</returns>
        public List<BaseElement> SearchPolygonElementsByXY(int x, int y)
        {
            List<BaseElement> res = new List<BaseElement>();
            if (_Manager != null)
            {
                List<BaseElement> elements = _Manager.Elements;
                for (int i = 0; i < elements.Count; i++)
                    if (elements[i].DrawOptions.CheckSelection(x, y) && !(elements[i] is Wire) && (elements[i] is CircuitElement))
                        res.Add(elements[i]);
            }
            return res;
        }

        /// <summary>
        /// Проинициализировать панель рисования в соответствии со схемой
        /// </summary>
        /// <param name="manager"></param>
        public void Init(ObjectManager manager)
        {
            _Manager = manager;
            if (manager != null)
            {
                Width = manager.SchemeCanvas.Width;
                Height = manager.SchemeCanvas.Height;
            }
            Refresh();
        }

        public void DeleteSelectedObject()
        {
            if ((_SelectedElement != null) && (_Manager != null))
            {
                _Manager.DisposeObject(_SelectedElement);
                this.Invalidate();
            }
        }

        public void ShowCanvasProperties()
        {
            CanvasPropertiesForm form = new CanvasPropertiesForm(_Manager);
            form.ShowDialog();

            this.Width = _Manager.SchemeCanvas.Width;
            this.Height = _Manager.SchemeCanvas.Height;
        }

        /// <summary>
        /// Сохранить изображение схемы
        /// </summary>
        /// <param name="filename">Имя файла</param>
        public void SaveImage(string filename)
        {
            GenerateImage().Save(filename);
        }

        #endregion

        #region Properties

        /// <summary>
        /// Управление схемой
        /// </summary>
        [Category("Management")]
        [Description("Менеджер объектов логической схемы")]
        public ObjectManager ObjManager
        {
            get
            {
                return _Manager;
            }
            set
            {
                _Manager = value;
            }
        }

        /// <summary>
        /// Палитра инструментов
        /// </summary>
        [Category("Management")]
        [Description("Панель инструментов рисования")]
        public IToolBox ToolBox
        {
            get
            {
                return _ToolBoxManager;
            }
            set
            {
                _ToolBoxManager = value;
            }
        }

        [Category("Drawings")]
        [Description("AntiAliasing")]
        [DefaultValue(SmoothingMode.Default)]
        public SmoothingMode DrawSmoothingMode
        {
            get
            {
                return _DrawSmoothing;
            }
            set
            {
                _DrawSmoothing = value;
            }
        }

        /// <summary>
        /// Масштаб для отображения
        /// </summary>
        [Category("Drawings")]
        [Description("Масштабирование холста")]
        [DefaultValue(1.0f)]
        public float CanvasScale
        {
            get
            {
                return _DrawingScale;
            }
            set
            {
                if (value > 0.0f)
                    _DrawingScale = value;
            }
        }

        [Category("Drawings")]
        [Description("Алгоритм масштабирования")]
        [DefaultValue(InterpolationMode.HighQualityBicubic)]
        public InterpolationMode ScaleInterpolation
        {
            get
            {
                return _Interpolation;
            }
            set
            {
                _Interpolation = value;
            }
        }

        /// <summary>
        /// Дискретность размещения объектов
        /// </summary>
        [Category("Drawings")]
        [Description("Сторона квадрата, образующего сетку дискретности для размещения элементов")]
        [DefaultValue(0)]
        public int Discreteness
        {
            get
            {
                return _Discreteness;
            }
            set
            {
                _Discreteness = value;
            }
        }

        #endregion
    }
}